package com.mate.cloud.redisnetworkmodel.AIO;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;

/**
 * AIO 实现 TCP 服务器（回调模式）
 * @author:         MI
 * @email:          448341911@qq.com
 * @createTime:     2025/9/3 14:30
 * @updateUser:     MI
 * @updateTime:     2025/9/3 14:30
 * @updateRemark:   修改内容
 * @version:        1.0
 */
public class AioTcpServer {

    public static void main(String[] args) throws IOException {
        // 1. 创建服务端异步通道（AsynchronousServerSocketChannel）
        AsynchronousServerSocketChannel serverChannel = AsynchronousServerSocketChannel.open();
        // 2. 绑定 8080 端口（异步通道无需设置“非阻塞”，本身就是异步的）
        serverChannel.bind(new InetSocketAddress(8080));
        System.out.println("AIO 服务器启动，监听 8080 端口...");

        // 3. 异步等待客户端连接（关键：调用 accept 方法，指定连接完成后的回调处理器）
        // 第一个参数：附件（可传递给回调的额外数据，这里传 null）
        // 第二个参数：连接完成处理器（CompletionHandler）
        serverChannel.accept(null, new CompletionHandler<AsynchronousSocketChannel, Void>() {
            // 3.1 连接成功时触发（OS 完成连接建立后调用）
            @Override
            public void completed(AsynchronousSocketChannel clientChannel, Void attachment) {
                try {
                    // 打印客户端连接信息
                    String clientAddr = clientChannel.getRemoteAddress().toString();
                    System.out.println("新客户端连接：" + clientAddr);

                    // ！！关键：再次调用 accept，继续等待下一个客户端连接（否则只能处理一个客户端）
                    serverChannel.accept(null, this);

                    // 4. 异步读取客户端数据（指定读取完成后的回调处理器）
                    // 准备缓冲区（附件传递客户端地址，方便回调中使用）
                    ByteBuffer buffer = ByteBuffer.allocate(1024);
                    clientChannel.read(buffer, clientAddr, new CompletionHandler<Integer, String>() {
                        // 4.1 读取数据成功时触发（OS 读取到数据后调用）
                        @Override
                        public void completed(Integer readLen, String clientAddr) {
                            if (readLen > 0) { // 读取到有效数据
                                // 切换缓冲区为读模式，解析数据
                                buffer.flip();
                                String clientMsg = new String(buffer.array(), 0, readLen);
                                System.out.println("收到[" + clientAddr + "]的消息：" + clientMsg);

                                // 5. 异步向客户端写入响应（指定写入完成后的回调处理器）
                                String response = "服务器已收到：" + clientMsg;
                                ByteBuffer responseBuffer = ByteBuffer.wrap(response.getBytes());
                                clientChannel.write(responseBuffer, clientAddr, new CompletionHandler<Integer, String>() {
                                    // 5.1 写入成功时触发
                                    @Override
                                    public void completed(Integer writeLen, String clientAddr) {
                                        System.out.println("向[" + clientAddr + "]发送响应成功，长度：" + writeLen);
                                        // 清空缓冲区，准备下一次读取（循环处理客户端后续消息）
                                        buffer.clear();
                                        clientChannel.read(buffer, clientAddr, this); // 再次异步读
                                    }

                                    // 5.2 写入失败时触发
                                    @Override
                                    public void failed(Throwable exc, String clientAddr) {
                                        System.err.println("向[" + clientAddr + "]发送响应失败：" + exc.getMessage());
                                        closeChannel(clientChannel); // 关闭通道
                                    }
                                });
                            } else if (readLen == -1) { // 客户端关闭连接（read 返回 -1）
                                System.out.println("客户端[" + clientAddr + "]主动关闭连接");
                                closeChannel(clientChannel);
                            }
                        }

                        // 4.2 读取数据失败时触发（如网络异常）
                        @Override
                        public void failed(Throwable exc, String clientAddr) {
                            System.err.println("读取[" + clientAddr + "]的数据失败：" + exc.getMessage());
                            closeChannel(clientChannel);
                        }
                    });

                } catch (IOException e) {
                    e.printStackTrace();
                }
            }

            // 3.2 连接失败时触发（如端口被占用）
            @Override
            public void failed(Throwable exc, Void attachment) {
                System.err.println("客户端连接失败：" + exc.getMessage());
            }
        });

        // ！！关键：主线程不能退出（AIO 用守护线程处理异步事件，主线程退出则程序结束）
        // 这里用休眠模拟主线程在处理其他任务（实际项目中主线程可能在处理配置、监控等）
        try {
            Thread.sleep(Long.MAX_VALUE);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    // 工具方法：关闭异步通道（避免资源泄漏）
    private static void closeChannel(AsynchronousSocketChannel channel) {
        if (channel != null && channel.isOpen()) {
            try {
                channel.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
